home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 April: Mac OS SDK / Dev.CD Apr 97 SDK1.toast / Development Kits (Disc 1) / AppleTalk Wide Area / XTI Shell Sample Code / XTIShell.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-02-17  |  35.1 KB  |  1,346 lines  |  [TEXT/MPS ]

  1. /*_________________________________________________________________________________
  2.  
  3.     File:        XTIShell.c
  4.     
  5.     This file contains the C routines called by XTIShell.a for the implementation 
  6.     of the AURP atlk calls.  It is based on the X25Tunnel atlk code and some X25 
  7.     specific things have been left in to provide an example.  Hints on things that 
  8.     may need to be changed are provided throughout.
  9.     
  10.     It is assumed that the implementation of XTI that the code was written to
  11.     (MacOSI) is standard enough that XTI specific changes will not need to be made.
  12.     This assumption has not yet been put to the test.  If you are not using MacOSI
  13.     or TII, be careful!
  14.     
  15.     Apple Computer, Inc. 
  16.     Copyright (C) 1992,1993.  All rights reserved.
  17.         
  18.     Revision History:
  19.     
  20. __________________________________________________________________________________*/
  21.  
  22. #include     <GestaltEqu.h>
  23. #include    <ToolUtils.h>
  24. #include    <String.h>
  25. #include    <Memory.h>
  26. #include    "AURPInterface.h"
  27. #include    "XTIShell.h"
  28. #include    "XTIShell_r.h"
  29.  
  30. /* ___ XTI flag bits ___ */
  31. #define        XTIInit                    0                        // bit 0, set if init'ed
  32. #define        XTIClose                1                        // bit 1, set if closing
  33. #define        XTILapInst                2                        // bit 2, set if LAP Write code is installed
  34.  
  35. /* ___ Log string indexes for our array ___ */
  36. #define        kDialLogIx                kDialLog-1        
  37. #define        kAnswerLogIx            kAnswerLog-1
  38. #define        kConnectLogIx            kConnectLog-1
  39. #define        kConnClearLogIx            kConnClearLog-1
  40. #define        kConnDownLogIx            kConnDownLog-1
  41. #define        kConnReqFailLogIx        kConnReqFailLog-1
  42. #define        kPasswordLogIx            kPasswordLog-1
  43.  
  44. //
  45. // This timer is used for both opening a connection and reconnecting.
  46. // You may eventually want to separate these timers, or put it in a resource
  47. // for fine tuning by you or the user if necessary.
  48. //
  49. /* ___ retry timer ___ */
  50. #define        kRetryTimer                10000                    // retry every 10 seconds
  51.  
  52. /* prototypes for the routines called from the assember code in XTIShell.a */
  53. OSErr    DOXTIINSTALL(XTIShellVarsPtr     myVarsPtr, XTIacfgPtr  aConfigPtr, TADEVSigRecPtr aSigPtr);
  54. OSErr    DOXTIDISCONNECT(XTIShellVarsPtr     myVarsPtr);
  55. OSErr    DOXTISHUTDOWN(XTIShellVarsPtr     myVarsPtr);
  56. OSErr     XTIWRITE(XTIShellVarsPtr myVarsPtr);
  57. OSErr     XTICONNECT(XTIShellVarsPtr myVarsPtr);
  58.  
  59. /* prototypes for the local routines */
  60. static void    do_try_open(void);
  61. static void    try_open(void);
  62. static int    try_reconnect( XTIShellVarsPtr myVarsPtr );
  63. static int    do_open( XTIShellVarsPtr myVarsPtr );
  64. static int    do_bind( XTIShellVarsPtr myVarsPtr );
  65. static void    do_connect( XTIShellVarsPtr myVarsPtr );
  66. static void    reconnect(void);
  67. static void    get_disconnect( XTIShellVarsPtr myVarsPtr );
  68. static void    doSendErr ( XTIShellVarsPtr myVarsPtr );
  69. static void    doReadErr ( XTIShellVarsPtr myVarsPtr );
  70. static void    get_data( XTIShellVarsPtr myVarsPtr );
  71. static void    get_connect( XTIShellVarsPtr myVarsPtr );
  72. static int    get_listen( XTIShellVarsPtr myVarsPtr );
  73. static void asyncReceive (int fd, int event, unsigned long providerInfo,int errno, void *cookie);
  74. static void    check_send( XTIShellVarsPtr myVarsPtr, int dataSent );
  75. static void Bin2Ascii(unsigned char *bin, unsigned char len, unsigned char *ascii);
  76. static XTIShellVarsPtr GETGLOBALS (void);
  77.  
  78. /*______________________________________________________________________________
  79.  
  80.     DOXTIINSTALL - Do the install.  Several modifications must be made in this
  81.                    routine.
  82.   
  83.     Returns:     error code
  84.     
  85.     Parameters:    --> myVarsPtr, aConfigPtr, aSigPtr
  86.     
  87. ______________________________________________________________________________*/
  88.  
  89. OSErr    DOXTIINSTALL(XTIShellVarsPtr    myVarsPtr, 
  90.                      XTIacfgPtr              aConfigPtr, 
  91.                      TADEVSigRecPtr     aSigPtr)
  92.  
  93. {
  94.     OSErr                result;
  95.     Ptr                    memBlockPtr;
  96.     char                i;
  97.     CShellGlobalsPtr    myGlobals;
  98.     long                ProcessorType;
  99.     ReOpenTMRecPtr        myReOpenTMRecPtr;
  100.     dtRecPtr            mydtRecPtr;
  101.     
  102.     
  103.     /* set up memcpy */
  104.     ProcessorType = gestalt68000;
  105.     result = Gestalt(gestaltProcessorType, &ProcessorType);
  106.     if (ProcessorType != gestalt68000)
  107.         memcpySetLongMove (ProcessorType);
  108.  
  109.     /* Get memory globals */
  110.     myVarsPtr->cGlobals = (CShellGlobalsPtr) GETSYSMEM(sizeof(CShellGlobals));
  111.     if (!myVarsPtr->cGlobals)
  112.         return(-1);
  113.     myGlobals = myVarsPtr->cGlobals;
  114.     
  115.     /* Get memory for log messages */
  116.     memBlockPtr = GETSYSMEM(kNumLogStr*kMaxLogStrLen);
  117.     if (!memBlockPtr)
  118.         return(-1);
  119.     
  120.     /* Get memory for time manager record */
  121.     myGlobals->openTMRec = (ReOpenTMRecPtr) GETSYSMEM (sizeof(ReOpenTMRec));
  122.     if (!myGlobals->openTMRec)
  123.         return(-1);
  124.     
  125.     /* Get memory for deferred task manager record */
  126.     myGlobals->mydtRec = (dtRecPtr) GETSYSMEM (sizeof(dtRec));
  127.     if (!myGlobals->mydtRec)
  128.         return(-1);
  129.     
  130.     /* initialize log string Ptrs */
  131.     for (i=0; i<kNumLogStr; i++) {
  132.         myGlobals->logStr[i] = memBlockPtr;
  133.         memBlockPtr += kMaxLogStrLen; 
  134.     }
  135.     
  136.     /* Get the log strings */
  137.     for (i=0; i< kNumLogStr; i++) {
  138.         GetIndString( (Str255) myGlobals->logStr[i], kXTILogStrID, i+1 );
  139.     }
  140.     
  141.     /* save config record */
  142.     myGlobals->theConfig = *aConfigPtr;
  143.             
  144.     /* initialize variables */
  145.     myGlobals->fd = -1;
  146.     myVarsPtr->otherNode = kNextIR;
  147. //
  148. // Fill in the appropriate line speed here.  If you don't know it until
  149. // the connection has been established, fill in your best guess and
  150. // put the correct information in later.
  151. //
  152.     myVarsPtr->lineSpeed = 9600;
  153.     myVarsPtr->OurSlotId = aSigPtr->slot;
  154.     myGlobals->bindComplete = false;
  155.     myGlobals->isConnected = false;
  156.     myGlobals->isReconnecting = false;
  157.     myGlobals->toldConnDone = false;
  158.     myGlobals->isFlowControlled = false;
  159.     myGlobals->isSending = false;
  160.     myGlobals->waitMoreData = false;
  161.     myVarsPtr->rcvBufAvail = true;
  162.     myVarsPtr->rcvPktsWaiting = 0;
  163.     myGlobals->waitForBind = false;
  164.     
  165. //
  166. // Fill in the maximum buffer size your link will allow here.  
  167. //
  168.     myVarsPtr->maxRPktSz = 618;
  169. //
  170. // The addressing scheme shown here is that of X.25.  This needs to be
  171. // changed to support the addressing scheme of the link you are using.
  172. //
  173.     myVarsPtr->remoteAddr[0] = 
  174.         myGlobals->theConfig.remoteAddr.ssaf.DTEaddr.X121Addr.len;
  175.     Bin2Ascii(myGlobals->theConfig.remoteAddr.ssaf.DTEaddr.X121Addr.addr,
  176.             myVarsPtr->remoteAddr[0],
  177.             &myVarsPtr->remoteAddr[1]);
  178.     
  179.     /* Get memory for receive  and send buffers */
  180.     myGlobals->sendBuffer = GETSYSMEM( myVarsPtr->maxRPktSz );
  181.     if (!myGlobals->sendBuffer) return(-1);
  182.     myGlobals->receiveBuffer = GETSYSMEM( myVarsPtr->maxRPktSz );
  183.     if (!myGlobals->receiveBuffer) return(-1);
  184.     
  185.     /* set up time manager variables for reconnect */
  186.     myGlobals->tmInfo.tmAddr = (TimerProcPtr) reconnect;
  187.     myGlobals->tmInfo.tmWakeUp = 0;
  188.     myGlobals->tmInfo.tmReserved = 0;
  189.     myGlobals->myA5 = GETMYA5();
  190.     
  191.     /* initialize deferred task manager record */
  192.     mydtRecPtr = myGlobals->mydtRec;
  193.     mydtRecPtr->qLink        = 0;
  194.     mydtRecPtr->qType         = dtQType;
  195.     mydtRecPtr->dtFlags        = 0;
  196.     mydtRecPtr->dtAddr         = (ProcPtr) try_open;
  197.     mydtRecPtr->dtParm         = 0;
  198.     mydtRecPtr->dtReserved     = 0;
  199.     
  200.     /* set up time manager variables for open */
  201.     myReOpenTMRecPtr = myGlobals->openTMRec;
  202.     myReOpenTMRecPtr->tmInfo.tmAddr = (TimerProcPtr) do_try_open;
  203.     myReOpenTMRecPtr->tmInfo.tmWakeUp = 0;
  204.     myReOpenTMRecPtr->tmInfo.tmReserved = 0;
  205.     
  206.     /* install time manager task */
  207.     if (myGlobals->theConfig.autoReconn) {
  208.         InsTime((QElemPtr) myGlobals);
  209.     }
  210.     InsTime((QElemPtr) myGlobals->openTMRec);
  211.             
  212.     return(0);
  213.  
  214.  
  215. /*______________________________________________________________________________
  216.     DOXTIDISCONNECT(XTIShellVarsPtr     myVarsPtr)
  217.     
  218.     Do the disconnect.   This code should not need any modifications.
  219.   
  220.     Returns:     error code
  221.     
  222.     Parameters:    --> myVarsPtr
  223. ______________________________________________________________________________*/
  224.  
  225. OSErr    DOXTIDISCONNECT(XTIShellVarsPtr     myVarsPtr)
  226.  
  227. {
  228.     CShellGlobalsPtr    myGlobals = myVarsPtr->cGlobals;
  229.     
  230.     myGlobals->isConnected = false;
  231.     myGlobals->isReconnecting = false;
  232.     myGlobals->toldConnDone = false;
  233.     
  234.     /* cancel outstanding writes */
  235.     if(myGlobals->isSending) {
  236.         myGlobals->isSending = false;
  237.         (*myVarsPtr->AURPDispatch)(kAURPWriteDone, myVarsPtr->AURPRefNum, myVarsPtr->wDSPtr, -1);
  238.     }
  239.  
  240.     /*  close the connection, don't care about unbind */
  241.     if (myGlobals->fd != -1) {    
  242.         t_close (myGlobals->fd);
  243.         myGlobals->fd = -1;
  244.     }
  245.     
  246.     return (0);
  247. }
  248.  
  249. /*______________________________________________________________________________
  250.     DOXTISHUTDOWN - Do the shutdown.  This code should not need any modifications
  251.                     unless additional memeory was allocated at AInstall time.
  252.   
  253.     Returns:     error code
  254.     
  255.     Parameters:    --> myVarsPtr
  256.     
  257.     Note:    Only call link tool if port info var is non-zero.                        
  258. ______________________________________________________________________________*/
  259.  
  260. OSErr    DOXTISHUTDOWN(XTIShellVarsPtr     myVarsPtr)
  261.  
  262. {
  263.     CShellGlobalsPtr    myGlobals = myVarsPtr->cGlobals;
  264.         
  265.     
  266.     /* Dispose the memory allocated in Install */
  267.     if (myVarsPtr->cGlobals) {
  268.     
  269.         if (myGlobals->theConfig.autoReconn && myGlobals->tmInfo.tmAddr) {
  270.             RmvTime((QElemPtr) myGlobals);
  271.         }
  272.         if(myGlobals->openTMRec->tmInfo.tmAddr)
  273.             RmvTime((QElemPtr) myGlobals->openTMRec);
  274.             
  275.         if (myGlobals->sendBuffer)
  276.             DisposPtr(myGlobals->sendBuffer);
  277.         if (myGlobals->receiveBuffer)
  278.             DisposPtr(myGlobals->receiveBuffer);
  279.         if (myGlobals->logStr[0])
  280.             DisposPtr(myGlobals->logStr[0]);
  281.         if (myGlobals->openTMRec)
  282.             DisposPtr((Ptr)myGlobals->openTMRec);
  283.             
  284.         DisposPtr((Ptr)myVarsPtr->cGlobals);
  285.         myVarsPtr->cGlobals = 0;
  286.     }
  287.     
  288.     return(noErr);
  289. }
  290.  
  291. /*____________________________________________________________________________
  292.     XTIWRITE (XTIShellVarsPtr myVarsPtr)
  293.     
  294.     Take a WDS element and write it out with t_snd.  This code should not need
  295.     any modification.
  296.     
  297.     Returns:    error code
  298.     
  299.     Parameters:    --> myVarsPtr
  300. ______________________________________________________________________________*/
  301.  
  302. OSErr XTIWRITE(XTIShellVarsPtr myVarsPtr)
  303. {
  304.     OSErr                error;
  305.     int                    event;
  306.     Ptr                    tempBuffer;
  307.     short                 i;
  308.     CShellGlobalsPtr    myGlobals = myVarsPtr->cGlobals;
  309.     
  310. //
  311. // If we are connected and not sending and the WDS element sent is not empty,
  312. // write out the packect.
  313. //
  314.     if(myGlobals->isConnected 
  315.         && !myGlobals->isSending
  316.         && myVarsPtr->wDSPtr[0].entryLength != 0) {
  317.         
  318.         /* copy wds element to send buffer */
  319.         myGlobals->sendBuffLen = 0;
  320.         tempBuffer = myGlobals->sendBuffer;
  321.         for(i = 0; myVarsPtr->wDSPtr[i].entryLength; i++) {
  322.             if (myGlobals->sendBuffLen+myVarsPtr->wDSPtr[i].entryLength > myVarsPtr->maxRPktSz) {
  323.                 return(-1);
  324.             }
  325.             memcpy (tempBuffer, myVarsPtr->wDSPtr[i].entryPtr, myVarsPtr->wDSPtr[i].entryLength);
  326.             myGlobals->sendBuffLen += myVarsPtr->wDSPtr[i].entryLength;
  327.             tempBuffer += myVarsPtr->wDSPtr[i].entryLength;
  328.         }
  329.         
  330.         /* now send the data */
  331.         myGlobals->isSending = true;
  332.         myGlobals->dataToSendPtr = myGlobals->sendBuffer;
  333.         error = t_snd( myGlobals->fd, myGlobals->dataToSendPtr, myGlobals->sendBuffLen, 0 );
  334.         if (error) {
  335.             /* check error */
  336.             switch (t_ERRNO( myGlobals->fd ))
  337.             {
  338.                 case TFLOW:
  339.                     myGlobals->isFlowControlled = true;
  340.                     break;
  341.                     
  342.                 case TLOOK:
  343.                     event = t_look ( myGlobals->fd ) ;
  344.                     if (event == T_DISCONNECT)
  345.                     {
  346.                         get_disconnect( myVarsPtr );
  347.                     }
  348.                     else doSendErr( myVarsPtr );    
  349.                     break;
  350.                     
  351.                 default:
  352.                     doSendErr( myVarsPtr );    
  353.                     break;
  354.                     
  355.             }
  356.         }
  357.         
  358.     }
  359.     else{
  360.         return( -1 );
  361.     }
  362.     
  363.     return( noErr );
  364.     
  365. }
  366.                 
  367.             
  368.  
  369.  
  370. /*____________________________________________________________________________
  371.     XTICONNECT (XTIShellVarsPtr myVarsPtr)
  372.     
  373.     This routine logs that we are trying to connect and sets up a time manager
  374.     task that will actually do the open.  This code should not need any
  375.     modifications.
  376.     
  377.     Returns:    error code
  378.     
  379.     Parameters:    --> myVarsPtr
  380. ______________________________________________________________________________*/
  381.  
  382. OSErr XTICONNECT(XTIShellVarsPtr myVarsPtr)
  383. {
  384.     CShellGlobalsPtr    myGlobals = myVarsPtr->cGlobals;
  385.     
  386.     
  387.     /* Log that we're initiating the connection */
  388.     if (myGlobals->theConfig.isCalling) 
  389.         (*myVarsPtr->AURPDispatch)(kAURPLogMsg, myVarsPtr->AURPRefNum, 0, myGlobals->logStr[kDialLogIx]);
  390.     else
  391.         (*myVarsPtr->AURPDispatch)(kAURPLogMsg, myVarsPtr->AURPRefNum, 0, myGlobals->logStr[kAnswerLogIx]);
  392.         
  393.     PrimeTime((QElemPtr) myGlobals->openTMRec, kRetryTimer);
  394.     
  395.     return( 0 );
  396. }
  397.  
  398. /*____________________________________________________________________________
  399.     do_try_open (void)
  400.     
  401.     This routine is called by the Time Manager (installed at connect time).  It
  402.     sets up a deferred task to try the t_open.  This code should not need any 
  403.     modifications.
  404.     
  405. ______________________________________________________________________________*/
  406. static void 
  407. do_try_open (void)
  408. {
  409.     OSErr                error;
  410.     XTIShellVarsPtr     myVarsPtr = GETGLOBALS();
  411.     CShellGlobalsPtr    myGlobals = myVarsPtr->cGlobals;
  412.     long                oldA5;
  413.  
  414.     oldA5 = GETMYA5();
  415.     SETMYA5(myGlobals->myA5);
  416.     
  417.     if ((error = DTInstall ((QElemPtr) myGlobals->mydtRec)) != noErr)
  418.         DebugStr ("\p Deferred Task Manager Returned Error");
  419.     
  420.     SETMYA5(oldA5);
  421.  
  422. }
  423.  
  424. /*____________________________________________________________________________
  425.     try_open (XTIShellVarsPtr myVarsPtr)
  426.     
  427.     This is the deferred task which does all the work for the connect sequence
  428.     (open, bind, connect).  Currently, it will continue to install itself (via 
  429.     the Time Manager routine) forever.  A suggestion for modification would be 
  430.     to set up a retry counter and limit the number of retries.
  431.  
  432. ______________________________________________________________________________*/
  433. static void
  434. try_open(void)
  435. {
  436.     XTIShellVarsPtr     myVarsPtr = GETGLOBALS();
  437.     CShellGlobalsPtr    myGlobals = myVarsPtr->cGlobals;
  438.     long                oldA5;
  439.     
  440.     oldA5 = GETMYA5();
  441.     SETMYA5(myGlobals->myA5);
  442.     
  443.         
  444. //
  445. // If waitForBind is true, we have already successfully opened an endpoint
  446. // and are waiting for a T_BINDCOMPLETE event.  Just check the bindComplete 
  447. // flag.  If it is true, we are done, otherwise, set up the time manager to
  448. // call us again.
  449. //
  450.     if(myGlobals->waitForBind) {
  451.         if(!myGlobals->bindComplete) {
  452.             PrimeTime((QElemPtr) myGlobals->openTMRec, kRetryTimer);
  453.             SETMYA5(oldA5);
  454.             return;
  455.         }
  456.         
  457.         myGlobals->waitForBind = false;
  458.         
  459. //
  460. // If the bind is complete, check if there was a bind error.  If there was,
  461. // disconnect and tell AURP we did not connect successfully.
  462. //
  463.         if(myGlobals->bindErr) {
  464.             DOXTIDISCONNECT(myVarsPtr);
  465.             SETMYA5(oldA5);
  466.             CONNDONE( -1 );
  467.             return;
  468.         }
  469.     }
  470.  
  471. //
  472. // If the open has not been successfully completed, try it.
  473. //
  474.     if(myGlobals->fd == -1) {
  475.         if(do_open(myVarsPtr)) {
  476.             PrimeTime((QElemPtr) myGlobals->openTMRec, kRetryTimer);    
  477.             SETMYA5(oldA5);
  478.             return;
  479.         }
  480.     }
  481.  
  482. //
  483. // The open has completed successfully, if the bind hasn't completed, try it.
  484. //
  485.     if(!myGlobals->bindComplete) {
  486.         if(do_bind(myVarsPtr)) {
  487. //
  488. // if the bind fails immediately, close the endpoint so we can try again
  489. //
  490.                 t_close(myGlobals->fd);
  491.                 myGlobals->fd = -1;
  492.             }
  493.         else {
  494. //
  495. // Because we are called by the time manager we have to leave the routine 
  496. // to allow for the T_BINDCOMPLETE event to be called.    
  497. //
  498.             myGlobals->waitForBind = true;
  499.         }
  500.         PrimeTime((QElemPtr) myGlobals->openTMRec, kRetryTimer);
  501.         SETMYA5(oldA5);
  502.         return;
  503.     }
  504.         
  505. //
  506. // The bind and open are complete.  If we are the calling router,
  507. // issue the connect.
  508. //
  509.     if (myGlobals->theConfig.isCalling) {
  510.         do_connect(myVarsPtr);
  511.     }
  512.     
  513.             
  514.     SETMYA5(oldA5);
  515.     return;
  516. }
  517.  
  518.  
  519. /*____________________________________________________________________________
  520.     try_reconnect (XTIShellVarsPtr myVarsPtr)
  521.     
  522.     If the user configuration specified automatic reconnection, install the
  523.     Time Manager routine to reconnect.    This code should not need any 
  524.     modifications.
  525.     
  526.     Returns:    error code
  527.     
  528.     Parameters: myVarsPtr
  529. ______________________________________________________________________________*/
  530. static int
  531. try_reconnect( XTIShellVarsPtr myVarsPtr )
  532. {
  533.     CShellGlobalsPtr    myGlobals = myVarsPtr->cGlobals;
  534.     
  535.         
  536.     if (myGlobals->theConfig.autoReconn) {
  537.         myGlobals->isReconnecting = true;
  538. //
  539. // If we are the calling router, delay the connect momentarily
  540. // to give the answering side a chance to start listening
  541. //
  542.         if (myGlobals->theConfig.isCalling)  {
  543.             PrimeTime((QElemPtr) myGlobals, kRetryTimer);
  544.         }
  545.         else {
  546.             return(XTICONNECT(myVarsPtr));
  547.         }
  548.     }
  549.     else {
  550.         DOXTIDISCONNECT(myVarsPtr);
  551.         return(-1);
  552.     }
  553.     
  554.     return(0);
  555. }
  556.  
  557.  
  558. /*____________________________________________________________________________
  559.     do_open (XTIShellVarsPtr myVarsPtr)
  560.     
  561.     This routine is called from the try_open routine.  It attempts a t_open. 
  562.     The slot ID is used as the provider name.  You may want to change this.
  563.     
  564.     Returns:    error code
  565.     
  566.     Parameters: myVarsPtr
  567. ______________________________________________________________________________*/
  568. static int
  569. do_open( XTIShellVarsPtr myVarsPtr )
  570. {
  571.     CShellGlobalsPtr    myGlobals = myVarsPtr->cGlobals;
  572.     struct t_info        info;
  573.     char                providerName[2];
  574.     
  575.  
  576. //
  577. // Set up and call the t_open.  This will be a non blocking endpoint.  
  578. // Unless absolutely necessary, it should be left non blocking.
  579. //
  580.     providerName[0] = 0;
  581.     providerName[1] = myVarsPtr->OurSlotId;
  582.     myGlobals->fd = t_open(providerName, O_NONBLOCK, &info );
  583.     if (myGlobals->fd == -1) {
  584.         return(-1);
  585.     }
  586.         
  587. //
  588. // Install the notifier completion routine.
  589. //
  590.     if (t_install_notifier (myGlobals->fd, asyncReceive, myVarsPtr)) 
  591.         return(-1);
  592.         
  593. //
  594. // By setting bindComplete to false, we are assured the bind will be
  595. // attempted on returning to the try_open routine.
  596. //
  597.     myGlobals->bindComplete = false;
  598.         
  599.     
  600.     return(0);
  601. }
  602.  
  603.  
  604. /*____________________________________________________________________________
  605.     do_bind (XTIShellVarsPtr myVarsPtr)
  606.     
  607.     This routine is called from the try_open routine after the t_open is 
  608.     complete.  It attempts a t_bind.  X.25 specific addressing is used and will 
  609.     need to changed.
  610.  
  611.     Returns:    error code
  612.     
  613.     Parameters: myVarsPtr
  614. ______________________________________________________________________________*/
  615. static int
  616. do_bind( XTIShellVarsPtr myVarsPtr )
  617. {
  618.     CShellGlobalsPtr    myGlobals = myVarsPtr->cGlobals;
  619.     struct     t_bind        bindRequest;
  620.     
  621.     bindRequest.addr.maxlen = sizeof(TTSAP);
  622.     bindRequest.addr.len =  sizeof(TTSAP);
  623.     bindRequest.addr.buf =  (char*) &myGlobals->theConfig.localAddr;
  624.     bindRequest.qlen = myGlobals->theConfig.isCalling ? 0 : 1;
  625.     
  626.     if (t_bind( myGlobals->fd, &bindRequest, nil ))
  627.         return(-1);
  628.     
  629.     return(0);
  630. }
  631.  
  632.  
  633. /*____________________________________________________________________________
  634.     do_connect (XTIShellVarsPtr myVarsPtr)
  635.     
  636.     This routine is called from the try_open routine after the open and bind are
  637.     complete.  It is called only if we are the calling router.  There is
  638.     X.25 specific address information here which will need to be modified.
  639.     
  640.     Returns:
  641.     
  642.     Parameters: myVarsPtr
  643. ______________________________________________________________________________*/
  644. static void
  645. do_connect( XTIShellVarsPtr myVarsPtr )
  646. {
  647.     CShellGlobalsPtr    myGlobals = myVarsPtr->cGlobals;
  648.     struct t_call        sndcall;
  649.     OSErr                error = noErr;
  650.     
  651. //
  652. // Set up the t_call structure.  Put in the correct address
  653. // for your particular link type.
  654. //
  655.     sndcall.addr.maxlen = sizeof(TTSAP);
  656.     sndcall.addr.len = sizeof(TTSAP);
  657.     sndcall.addr.buf =  (char*) &myGlobals->theConfig.remoteAddr;
  658.     sndcall.opt.maxlen = 0;
  659.     sndcall.opt.len = 0;
  660.     sndcall.udata.maxlen = 0;
  661.     sndcall.udata.len = 0;
  662.         
  663. //
  664. // Make the t_connect call.  It will return -1 since we are asynchronous
  665. //
  666.     t_connect( myGlobals->fd, &sndcall, nil ) ;
  667. //
  668. // Check the actual error
  669. //
  670.     error = t_ERRNO( myGlobals->fd );
  671.     if(error != TNODATA)  {    
  672. //
  673. // If a T_NODATA error occurred, we are stuck.  Log the connection not
  674. // established message, disconnect, and tell AURP the connection failed.
  675. //
  676.         (*myVarsPtr->AURPDispatch)(kAURPLogMsg, myVarsPtr->AURPRefNum, 0, myGlobals->logStr[kConnReqFailLogIx]);
  677.         DOXTIDISCONNECT(myVarsPtr);
  678.         CONNDONE( -1 );
  679.     }
  680.  
  681. }
  682.  
  683.  
  684. /*____________________________________________________________________________
  685.     reconnect (void)
  686.     
  687.     The Time Manager reconnect routine.  Installed by try_reconnect routine
  688.     which is called whenever we think the connection has dropped and we
  689.     want to attempt to reconnect.  This code should not need any modifications.
  690.     
  691.     Returns:
  692.     
  693.     Parameters: 
  694. ______________________________________________________________________________*/
  695. static void
  696. reconnect(void)
  697. {
  698.     XTIShellVarsPtr     myVarsPtr = GETGLOBALS();
  699.     CShellGlobalsPtr    myGlobals = myVarsPtr->cGlobals;
  700.     long                oldA5;
  701.     
  702.     oldA5 = GETMYA5();
  703.     SETMYA5(myGlobals->myA5);
  704.     
  705.             
  706.     if(XTICONNECT(myVarsPtr))  {
  707.         CONNDONE( -1 );
  708.     }
  709.     
  710.     SETMYA5(oldA5);
  711.  
  712. }
  713.  
  714.  
  715. /*____________________________________________________________________________
  716.     get_disconnect (XTIShellVarsPtr myVarsPtr)
  717.     
  718.     A disconnect event has been received on the endpoint, go get it.  This 
  719.     code should not need any modifications.
  720.     
  721.     Returns:    error code
  722.     
  723.     Parameters: myVarsPtr
  724. ______________________________________________________________________________*/
  725. static void
  726. get_disconnect( XTIShellVarsPtr myVarsPtr )
  727. {
  728.     CShellGlobalsPtr    myGlobals = myVarsPtr->cGlobals;
  729.     struct t_discon        myDisconnect;
  730.     
  731.     
  732.     myDisconnect.udata.maxlen = 0;
  733.     myDisconnect.udata.buf = nil;
  734.     myDisconnect.udata.len = 0;
  735.     myDisconnect.reason = 0;
  736.     myDisconnect.sequence = 0;
  737.  
  738. //
  739. // Receive the disconnect event.  We don't care what the error
  740. // returned is because we are going to disconnect anyway.
  741. //
  742.     t_rcvdis( myGlobals->fd, &myDisconnect );    
  743.  
  744. //
  745. // If we were connected, log the connection went down message, otherwise log
  746. // the connection request refused message.
  747. //
  748.     if (myGlobals->isConnected)
  749.         (*myVarsPtr->AURPDispatch)(kAURPLogMsg, myVarsPtr->AURPRefNum, 0, myGlobals->logStr[kConnDownLogIx]);
  750.     else {    
  751.         (*myVarsPtr->AURPDispatch)(kAURPLogMsg, myVarsPtr->AURPRefNum, 0, myGlobals->logStr[kConnClearLogIx]);
  752.     }
  753.     myGlobals->isConnected = false;
  754.     
  755. //
  756. // Complete the disconnect
  757. //
  758.     DOXTIDISCONNECT(myVarsPtr);
  759. //
  760. // Attempt to reconnect
  761. //
  762.     if (try_reconnect(myVarsPtr))  {
  763.         CONNDONE( -1 );
  764.     }
  765. }
  766.  
  767. /*____________________________________________________________________________
  768.     doSendErr (XTIShellVarsPtr myVarsPtr)
  769.     
  770.     This routine is called when a send error occurs.  Assume the connection
  771.     has gone down.  This code should not need any modifications.
  772.     
  773.     Returns:
  774.     
  775.     Parameters: myVarsPtr
  776. ______________________________________________________________________________*/
  777. static void
  778. doSendErr ( XTIShellVarsPtr myVarsPtr )
  779. {
  780.     CShellGlobalsPtr    myGlobals = myVarsPtr->cGlobals;
  781.  
  782. //
  783. // Log that the connection went down and complete disconnection
  784. //
  785.     (*myVarsPtr->AURPDispatch)(kAURPLogMsg, myVarsPtr->AURPRefNum, 0, myGlobals->logStr[kConnDownLogIx]);
  786.     DOXTIDISCONNECT(myVarsPtr);
  787. //
  788. // Attempt to reconnect
  789. //
  790.     if(try_reconnect(myVarsPtr)) 
  791.         CONNDONE( -1 );
  792.     
  793. }
  794.  
  795. /*____________________________________________________________________________
  796.     doReadErr (XTIShellVarsPtr myVarsPtr)
  797.     
  798.     This routine is called when a read error occurs.  Assume the connection 
  799.     went down.  This code should not need any modifications.
  800.     
  801.     Returns:
  802.     
  803.     Parameters: myVarsPtr
  804. ______________________________________________________________________________*/
  805. static void
  806. doReadErr ( XTIShellVarsPtr myVarsPtr )
  807. {
  808.     CShellGlobalsPtr    myGlobals = myVarsPtr->cGlobals;
  809.  
  810. //
  811. // Log that the connection went down and complete disconnection
  812. //
  813.     (*myVarsPtr->AURPDispatch)(kAURPLogMsg, myVarsPtr->AURPRefNum, 0, myGlobals->logStr[kConnDownLogIx]);
  814.     DOXTIDISCONNECT(myVarsPtr);
  815.  
  816. //
  817. // Attempt to reconnect
  818. //
  819.     if(try_reconnect(myVarsPtr)) 
  820.         CONNDONE( -1 );
  821.     
  822. }
  823.     
  824.  
  825.  
  826. /*____________________________________________________________________________
  827.     READDONE (XTIShellVarsPtr myVarsPtr)
  828.     
  829.     This routine is called from assembly when the read buffer is returned from
  830.     AURP.  It is only called if data is outstanding.  This code should not need 
  831.     any modifications.
  832.     
  833.     Returns:
  834.     
  835.     Parameters:    myVarsPtr
  836. ______________________________________________________________________________*/
  837. void
  838. READDONE( XTIShellVarsPtr myVarsPtr )
  839. {
  840. //
  841. // Decrement the number of packets waiting to be read and get the data
  842. //
  843.     myVarsPtr->rcvPktsWaiting--;
  844.     get_data( myVarsPtr );
  845. }
  846.     
  847.  
  848.  
  849. /*____________________________________________________________________________
  850.     get_data (XTIShellVarsPtr myVarsPtr)
  851.     
  852.     This routine is called to get data that is waiting to be read.  This data 
  853.     is not necessarily a complete packet.  It is called by READDONE and when a 
  854.     T_DATA event is received.  This code should not need any modifications.
  855.     
  856.     Returns:
  857.     
  858.     Parameters:    myVarsPtr
  859. ______________________________________________________________________________*/
  860. static void
  861. get_data( XTIShellVarsPtr myVarsPtr )
  862. {
  863.     int                    bytesRead;
  864.     int                    flags;
  865.     Boolean                gotEndOfBuffer = false;
  866.     char                *buf;
  867.     OSErr                error = noErr;
  868.     int                    event;
  869.     CShellGlobalsPtr    myGlobals = myVarsPtr->cGlobals;
  870.     long                sr;
  871.     
  872.     buf = myGlobals->receiveBuffer;
  873. //
  874. // If we are in waitMoreData state, the receiveBuffer is "empty"
  875. //
  876.     if (!myGlobals->waitMoreData) {
  877.         myGlobals->rcvBuffLen = 0;
  878.         myVarsPtr->rcvBufAvail = false;  /* flag is cleared in the assembler routine */
  879.     }
  880.     else {
  881.         myGlobals->waitMoreData = false;
  882.     }
  883.     
  884. //
  885. // Read until we get a complete packet or there is no more data to be read
  886. //
  887.     while(!error && !gotEndOfBuffer) {
  888.         flags = 0;
  889.         bytesRead = t_rcv( myGlobals->fd, &(buf[myGlobals->rcvBuffLen]), 
  890.                            myVarsPtr->maxRPktSz - myGlobals->rcvBuffLen, &flags );
  891. //
  892. // bytesRead equal to -1 indicates an error, find out what it is
  893. //
  894.         if (bytesRead == -1) {
  895.             error = t_ERRNO( myGlobals->fd );
  896.         }
  897.         else {
  898.             myGlobals->rcvBuffLen += bytesRead;
  899. //
  900. // If we have received more than we asked for, we have serious problems,
  901. // so tear down the connection
  902. //
  903.             if (myGlobals->rcvBuffLen > myVarsPtr->maxRPktSz)  {
  904.                 (*myVarsPtr->AURPDispatch)(kAURPLogMsg, myVarsPtr->AURPRefNum, 0, myGlobals->logStr[kConnDownLogIx]);
  905.                 DOXTIDISCONNECT(myVarsPtr);
  906.                 CONNDONE( -1 );
  907.                 return;
  908.             }
  909. //
  910. // If the T_MORE flag isn't set, the packet is complete
  911. //
  912.             if (!(flags & T_MORE)) 
  913.                 gotEndOfBuffer = true;
  914.         } 
  915.     }
  916.     
  917. //
  918. // If we got the whole buffer, save the interrupt level and
  919. // give the buffer to AURP.  
  920. //
  921.     if (gotEndOfBuffer) {
  922.         sr = GETSR ();
  923.         (*myVarsPtr->AURPDispatch)(kAURPRead, myVarsPtr->AURPRefNum, 
  924.                                      myVarsPtr->otherNode, myGlobals->rcvBuffLen, buf);
  925.     }
  926.     
  927. //
  928. // If there was an error, check it and take appropriate action.
  929. //
  930.     if (error) {
  931.             switch (error)
  932.             {
  933.                 case TNODATA:
  934. //
  935. // This is the case where we did not receive the complete packet
  936. // so we still have a partial buffer.
  937. //
  938.                     myGlobals->waitMoreData = true;
  939.                     break;
  940.                     
  941.                 case TLOOK:
  942.                     event = t_look ( myGlobals->fd ) ;
  943.                     if (event == T_DISCONNECT)
  944.                     {
  945.                         get_disconnect( myVarsPtr );
  946.                     }
  947.                     else doReadErr( myVarsPtr );
  948.                     return;
  949.                 default:
  950.                     doReadErr( myVarsPtr );    
  951.                     return;
  952.             }
  953.         }
  954.     
  955.     return;
  956. }
  957.  
  958. /*____________________________________________________________________________
  959.     get_connect (XTIShellVarsPtr myVarsPtr)
  960.     
  961.     This routine is called when a T_CONNECT event is received.  Go get the
  962.     connect.  This code should not need any modifications.
  963.     
  964.     Returns:
  965.     
  966.     Parameters:    myVarsPtr
  967. ______________________________________________________________________________*/
  968. static void
  969. get_connect( XTIShellVarsPtr myVarsPtr )
  970. {
  971.     CShellGlobalsPtr    myGlobals = myVarsPtr->cGlobals;
  972.     
  973.  
  974.     if (t_rcvconnect( myGlobals->fd, nil ))
  975.     {
  976. //
  977. // If an error occurred on the receive connect, log
  978. // the connection not established message, disconnect,
  979. // and tell AURP the connection failed.
  980. //
  981.         (*myVarsPtr->AURPDispatch)(kAURPLogMsg, myVarsPtr->AURPRefNum, 0, myGlobals->logStr[kConnReqFailLogIx]);
  982.         DOXTIDISCONNECT(myVarsPtr);
  983.         if(try_reconnect(myVarsPtr)) 
  984.             CONNDONE( -1 );
  985.             return;
  986.     } else {
  987.         myGlobals->isConnected = true;
  988.     
  989. //
  990. // Log the connection established message and tell AURP
  991. // the connection was successful.
  992. //
  993.         (*myVarsPtr->AURPDispatch)(kAURPLogMsg, myVarsPtr->AURPRefNum, 0, myGlobals->logStr[kConnectLogIx]);
  994.         if(!myGlobals->toldConnDone) {
  995.             CONNDONE( 0 );
  996.             myGlobals->toldConnDone = false;
  997.         }
  998.             
  999.         myGlobals->isReconnecting = false;
  1000.     }    
  1001. }
  1002.  
  1003. /*____________________________________________________________________________
  1004.     get_listen (XTIShellVarsPtr myVarsPtr) 
  1005.     
  1006.     This routine is called when a T_LISTEN event occurs.  If password
  1007.     protection is desired, code should be added to verify it before
  1008.     accepting the connection.
  1009.     
  1010.     Returns:    error code
  1011.     
  1012.     Parameters: myVarsPtr
  1013. ______________________________________________________________________________*/
  1014. static int
  1015. get_listen( XTIShellVarsPtr myVarsPtr )
  1016. {
  1017.     struct t_call        call;
  1018.     CShellGlobalsPtr    myGlobals = myVarsPtr->cGlobals;
  1019.     
  1020.     
  1021.     call.addr.buf =   (char*) &myGlobals->theConfig.remoteAddr;
  1022.     call.addr.maxlen = sizeof(TTSAP);
  1023.     call.opt.buf = nil;
  1024.     call.udata.maxlen = 0;
  1025.     call.udata.buf = nil;
  1026.     
  1027. //
  1028. // Get the listen event.  If we fail to get it, log connection down,
  1029. // disconnect, and try to reconnect.
  1030. //
  1031.     if (t_listen( myGlobals->fd, &call ))
  1032.     {       
  1033.         (*myVarsPtr->AURPDispatch)(kAURPLogMsg, myVarsPtr->AURPRefNum, 0, myGlobals->logStr[kConnDownLogIx]);
  1034.         DOXTIDISCONNECT(myVarsPtr);
  1035.         return( try_reconnect(myVarsPtr) );
  1036.  
  1037.     }
  1038.         
  1039. //
  1040. // Accept the connection.
  1041. //
  1042.     if ( t_accept(myGlobals->fd, myGlobals->fd, &call ) )
  1043.     {    
  1044. //
  1045. // If an error occurs on the t_accept, log connection down, disconnect,
  1046. // and try to reconnect.
  1047. //
  1048.         (*myVarsPtr->AURPDispatch)(kAURPLogMsg, myVarsPtr->AURPRefNum, 0, myGlobals->logStr[kConnDownLogIx]);
  1049.         DOXTIDISCONNECT(myVarsPtr);
  1050.         return( try_reconnect(myVarsPtr) );
  1051.     }
  1052.     
  1053.     return(0);
  1054.     
  1055. }
  1056.  
  1057. /*____________________________________________________________________________
  1058.     check_send ( XTIShellVarsPtr myVarsPtr, int dataSent )
  1059.     
  1060.     This routine is called when a T_SENDCOMPLETE event occurs.  Check
  1061.     the results and act accordingly.  This code should not need any
  1062.     modifications.
  1063.     
  1064.     Returns:
  1065.     
  1066.     Parameters:    myVarsPtr,    dataSent
  1067. ______________________________________________________________________________*/
  1068.  
  1069. static void    check_send( XTIShellVarsPtr myVarsPtr, int dataSent ) {
  1070.     CShellGlobalsPtr    myGlobals;
  1071.     int                    event;
  1072.     
  1073.     
  1074.     myGlobals = myVarsPtr->cGlobals;
  1075.  
  1076. //
  1077. // If the dataSent is less than the buffer length, all the
  1078. // data was not sent so send the rest of it.
  1079. //
  1080.         if (dataSent < myGlobals->sendBuffLen) 
  1081.         {
  1082.             myGlobals->sendBuffLen -= dataSent;
  1083.             myGlobals->dataToSendPtr += dataSent;
  1084.             if (t_snd( myGlobals->fd, myGlobals->dataToSendPtr, myGlobals->sendBuffLen, 0 )) {
  1085. //
  1086. // If the t_snd failed, find out why.
  1087. //
  1088.                 switch (t_ERRNO( myGlobals->fd ))
  1089.                 {
  1090.                     case TFLOW:
  1091.                         myGlobals->isFlowControlled = true;
  1092.                         break;
  1093.                         
  1094.                     case TLOOK:
  1095.                         event = t_look ( myGlobals->fd ) ;
  1096.                         if (event == T_DISCONNECT)
  1097.                         {
  1098.                             get_disconnect( myVarsPtr );
  1099.                         }
  1100.                         else doSendErr( myVarsPtr );    
  1101.                         break;
  1102.                         
  1103.                     default:
  1104.                         doSendErr( myVarsPtr );    
  1105.                         break;
  1106.                         
  1107.                 }
  1108.             }
  1109.         }
  1110.         else 
  1111.         {
  1112. //
  1113. // All the data was successfully sent.  Tell AURP the write
  1114. // is complete.
  1115. //
  1116.             myGlobals->isSending = false;
  1117.             (*myVarsPtr->AURPDispatch)(kAURPWriteDone, myVarsPtr->AURPRefNum, myVarsPtr->wDSPtr, 0);
  1118.         }
  1119.             
  1120. }
  1121.  
  1122. /*____________________________________________________________________________
  1123.     AsyncReceive (int fd, int event, unsigned long providerInfo,
  1124.                                         int errno, void *cookie)
  1125.                         
  1126.     This is the installed completion routine.  All XTI events are processed 
  1127.     here.  The procedure for each event is basically the same - if there
  1128.     was an error, log a connection down error message, disconnect, and tell
  1129.     AURP.  Otherwise, call a routine to handle the event.  This routine should 
  1130.     not need to be modified unless you want to perform different or
  1131.     additional error handling.
  1132.     
  1133.     Returns:
  1134.     
  1135.     Parameters:    fd, event, providerInfo, errNo, -> cookie
  1136. ______________________________________________________________________________*/
  1137.  
  1138. static void asyncReceive (int fd, int event, unsigned long providerInfo,
  1139.                                             int errno, void *cookie)
  1140. {
  1141. #pragma unused (providerInfo)
  1142.     XTIShellVarsPtr        myVarsPtr;
  1143.     CShellGlobalsPtr    myGlobals;
  1144.     
  1145.     
  1146.  
  1147.     myVarsPtr = (XTIShellVarsPtr) cookie;
  1148.     myGlobals = myVarsPtr->cGlobals;
  1149.         
  1150.     switch (event)
  1151.     {
  1152.         case T_BINDCOMPLETE:
  1153. //
  1154. // An outstanding bind request has completed
  1155. //
  1156.             myGlobals->bindComplete = true;
  1157.             myGlobals->bindErr = errno;
  1158.             if(errno) {
  1159.                 break;
  1160.             }
  1161.             myGlobals->bindErr = t_rcvbind (fd, nil);
  1162.             if(myGlobals->bindErr) {
  1163.                 (*myVarsPtr->AURPDispatch)(kAURPLogMsg, myVarsPtr->AURPRefNum, 0, myGlobals->logStr[kConnReqFailLogIx]);
  1164.                 break;
  1165.             }
  1166.             break;
  1167.             
  1168.         case T_CONNECT:
  1169. //
  1170. // You are the calling router and a connect response
  1171. // to your connect request has been received.
  1172. //
  1173.             if (errno)
  1174.             {        
  1175.                 (*myVarsPtr->AURPDispatch)(kAURPLogMsg, myVarsPtr->AURPRefNum, 0, myGlobals->logStr[kConnDownLogIx]);
  1176.                 DOXTIDISCONNECT(myVarsPtr);
  1177.                 if(try_reconnect(myVarsPtr)) 
  1178.                     CONNDONE( -1 );
  1179.                 break;
  1180.             }
  1181.             
  1182.             get_connect( myVarsPtr );
  1183.             
  1184.             break;
  1185.             
  1186.         case T_DISCONNECT:
  1187. //
  1188. // A router is trying to disconnect
  1189. //
  1190.             if (errno) {
  1191.                 DOXTIDISCONNECT(myVarsPtr);
  1192.                 if(try_reconnect(myVarsPtr)) 
  1193.                     CONNDONE( -1 );
  1194.                 break;
  1195.             }
  1196.             
  1197.             get_disconnect( myVarsPtr );
  1198.             
  1199.             break;
  1200.             
  1201.         case T_PASSCON:
  1202. //
  1203. // You are the answering router and the connection you accepted
  1204. // is now complete.
  1205. //
  1206.             if (errno)
  1207.             {        
  1208.                 (*myVarsPtr->AURPDispatch)(kAURPLogMsg, myVarsPtr->AURPRefNum, 0, myGlobals->logStr[kConnDownLogIx]);
  1209.                 DOXTIDISCONNECT(myVarsPtr);
  1210.                 if(try_reconnect(myVarsPtr)) 
  1211.                     CONNDONE( -1 );
  1212.                 break;
  1213.             }
  1214.                         
  1215.             myGlobals->isConnected = true;
  1216.             // log connection established message
  1217.             (*myVarsPtr->AURPDispatch)(kAURPLogMsg, myVarsPtr->AURPRefNum, 0, myGlobals->logStr[kConnectLogIx]);
  1218.  
  1219.             if(!myGlobals->toldConnDone) {
  1220.                 CONNDONE( 0 );
  1221.                 myGlobals->toldConnDone = false;
  1222.             }
  1223.             myGlobals->isReconnecting = false;    
  1224.             
  1225.         case T_GODATA:
  1226. //
  1227. // The connection was flow controlled, but now it is not.
  1228. //
  1229.             if (errno == -1)
  1230.             {        
  1231.                 (*myVarsPtr->AURPDispatch)(kAURPLogMsg, myVarsPtr->AURPRefNum, 0, myGlobals->logStr[kConnDownLogIx]);
  1232.                 DOXTIDISCONNECT(myVarsPtr);
  1233.                 if(try_reconnect(myVarsPtr)) 
  1234.                     CONNDONE( -1 );
  1235.                 break;
  1236.             }
  1237.             
  1238. //
  1239. // T_GODATA is the same as T_SENDCOMPLETE, only 0 bytes are sent 
  1240. //
  1241.             myGlobals->isFlowControlled = false;
  1242.             errno = 0;
  1243. //
  1244. // continue with the code for T_SENDCOMPLETE 
  1245. //
  1246.             
  1247.         case T_SENDCOMPLETE:
  1248. //
  1249. // A outstanding send is complete
  1250. //
  1251.             if (errno == -1)
  1252.             {        
  1253.                 (*myVarsPtr->AURPDispatch)(kAURPLogMsg, myVarsPtr->AURPRefNum, 0, myGlobals->logStr[kConnDownLogIx]);
  1254.                 DOXTIDISCONNECT(myVarsPtr);
  1255.                 if(try_reconnect(myVarsPtr)) 
  1256.                     CONNDONE( -1 );
  1257.                 break;
  1258.             }
  1259.             
  1260.             check_send(myVarsPtr, errno);
  1261.             break;
  1262.             
  1263.         case T_LISTEN:
  1264. //
  1265. // You are the answering router and a connect request
  1266. // has been received.
  1267. //
  1268.             if (errno)
  1269.             {        
  1270.                 (*myVarsPtr->AURPDispatch)(kAURPLogMsg, myVarsPtr->AURPRefNum, 0, myGlobals->logStr[kConnDownLogIx]);
  1271.                 DOXTIDISCONNECT(myVarsPtr);
  1272.                 if(try_reconnect(myVarsPtr)) 
  1273.                     CONNDONE( -1 );
  1274.                 break;
  1275.             }
  1276.             
  1277.             if(get_listen( myVarsPtr ))
  1278.             {        
  1279.                 (*myVarsPtr->AURPDispatch)(kAURPLogMsg, myVarsPtr->AURPRefNum, 0, myGlobals->logStr[kConnDownLogIx]);
  1280.                 DOXTIDISCONNECT(myVarsPtr);
  1281.                 if(try_reconnect(myVarsPtr)) 
  1282.                     CONNDONE( -1 );
  1283.                 break;
  1284.             }
  1285.                 
  1286.             break;
  1287.             
  1288.         case T_DATA:
  1289. //
  1290. // Data has been received.
  1291. //
  1292.             if (errno)
  1293.             {        
  1294.                 (*myVarsPtr->AURPDispatch)(kAURPLogMsg, myVarsPtr->AURPRefNum, 0, myGlobals->logStr[kConnDownLogIx]);
  1295.                 DOXTIDISCONNECT(myVarsPtr);
  1296.                 if(try_reconnect(myVarsPtr)) 
  1297.                     CONNDONE( -1 );
  1298.                 break;
  1299.             }
  1300.             
  1301.             if (myVarsPtr->rcvBufAvail || myGlobals->waitMoreData) {
  1302.                 get_data( myVarsPtr );
  1303.             } else {
  1304.                 myVarsPtr->rcvPktsWaiting++;
  1305.             }
  1306.             break;
  1307.             
  1308.         default:
  1309.             DOXTIDISCONNECT(myVarsPtr);
  1310.         
  1311.             if(try_reconnect(myVarsPtr)) 
  1312.                 CONNDONE( -1 );
  1313.             
  1314.             break;
  1315.     }
  1316.  
  1317.     return;
  1318. }
  1319.  
  1320. /************************/
  1321. /*     Bin2Ascii            */
  1322. /************************/
  1323. static void Bin2Ascii(unsigned char *bin, unsigned char len, unsigned char *ascii)
  1324. {
  1325.     unsigned char cnt;
  1326.  
  1327.     for (cnt = 0; cnt < len; cnt++) {
  1328.         if (cnt & 0x01) {
  1329.             ascii[cnt] = bin[cnt >> 1] & 0x0F;
  1330.         } else {
  1331.             ascii[cnt] = bin[cnt >> 1] >> 4;
  1332.         }
  1333.         
  1334.         
  1335.         
  1336.         if (ascii[cnt] >= 0x0A && ascii[cnt] <= 0x0F) {
  1337.             ascii[cnt] +=  'A';
  1338.         } 
  1339.         else {
  1340.             ascii[cnt] +=  '0';
  1341.         } 
  1342.  
  1343.     }
  1344.     return;
  1345. }